/******************************************************************************

    SlkAction.c

    Version 7.51

    semantic actions that are invoked by their index through the call table.

    Copyright (c) 2002-2014  SLK Systems, all rights reserved.
    
******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "SlkAction.h"

// -----------------------------------------------------------------------
// semantic stack action code
// -----------------------------------------------------------------------

#undef push 
#undef pop

#define push(n,s) if (s.top > s.start) { *--s.top = n; }\
        else { puts ("tree: stack overflow"); exit(1); }

#define pop(s)   ( s.top < s.end ? *s.top++ : *s.top )

PRIVATE 
void
dump_stack ( stack3_t   s )                        // debugging
{
    double   *top;

    for ( top = s.top;  *top;  ++top ) {
        printf ( "%f ", *top );
    }
    putchar ( '\n' );
}

// -----------------------------------------------------------------------
// abstract syntax tree action code
// -----------------------------------------------------------------------

PRIVATE
node2_t *
make_node ( double    item,
            node2_t  *left,
            node2_t  *right )
{
    register
    node2_t    *node;

    node = malloc ( sizeof ( node2_t ) );
    if ( node == NULL ) {
        puts ( "malloc failed\n" );
        exit (1);
    }
    node->item = item;
    node->left = left;
    node->right = right;

    return ( node );
}

PRIVATE 
double
post_order_r ( node2_t  *tree )
{
    double  left,
            right,
            value;

    if ( tree == NULL ) {
        return  0;
    }
    left = post_order_r ( tree->left );
    right = post_order_r ( tree->right );
    switch ( (int) tree->item ) {
        case '-' :
            if ( right ) {
                value = left - right;
            } else {
                value = -left;
            }
            printf ( " %c ", (char) tree->item );
            break;
        case '+' :
            value = left + right;
            printf ( " %c ", (char) tree->item );
            break;
        case '/' :
            value = left / right;
            printf ( " %c ", (char) tree->item );
            break;
        case '*' :
            value = left * right;
            printf ( " %c ", (char) tree->item );
            break;
        case '^' :
            value = pow ( left, (int) right );
            printf ( " %c ", (char) tree->item );
            break;
        default :
            value = tree->item ;
            printf ( " %.2f ", tree->item );
    }

    return  value;
}

PRIVATE 
double
(post_order) ( action_t  *d )
{
    return  post_order_r ( d->abstract_root );
}

PRIVATE 
void
(state) ( action_t  *d, 
          slk_size_t number )
{
}

// -----------------------------------------------------------------------
// grammar action code functions
//
// Duplicate action methods are illustrated. The first part of each action
// function computes the d->answer directly. The second part builds an
// d->abstract syntax tree to be processed later in main.
// -----------------------------------------------------------------------

PRIVATE 
void Add ( action_t  *d )
{
    double   op;
    node2_t  *node;

    d->answer = pop ( d->semantic_stack );                        // direct action
    op = pop ( d->semantic_stack );
    if ( op == '+' ) {
        d->answer = pop ( d->semantic_stack ) + d->answer;
    } else {
        d->answer = pop ( d->semantic_stack ) - d->answer;
    }
    push ( d->answer, d->semantic_stack );

    node = pop ( d->abstract_stack );                          // d->abstract syntax tree
    d->abstract_root = pop ( d->abstract_stack );
    d->abstract_root->left = pop ( d->abstract_stack );
    d->abstract_root->right = node;
    push ( d->abstract_root, d->abstract_stack );
}

PRIVATE 
void Finish ( action_t  *d )
{
    d->answer = pop ( d->semantic_stack );

    d->abstract_root = pop ( d->abstract_stack );
}

PRIVATE 
void Multiply ( action_t  *d )
{
    double   op;
    node2_t  *node;

    d->answer = pop ( d->semantic_stack );
    op = pop ( d->semantic_stack );
    if ( op == '*' ) {
        d->answer = pop ( d->semantic_stack ) * d->answer;
    } else {
        d->answer = pop ( d->semantic_stack ) / d->answer;
    }
    push ( d->answer, d->semantic_stack );

    node = pop ( d->abstract_stack );
    d->abstract_root = pop ( d->abstract_stack );
    d->abstract_root->left = pop ( d->abstract_stack );
    d->abstract_root->right = node;
    push ( d->abstract_root, d->abstract_stack );
}

PRIVATE 
void Exponent ( action_t  *d )
{
    d->answer = pop ( d->semantic_stack );
    d->answer = pow ( pop ( d->semantic_stack ), (int) d->answer );
    push ( d->answer, d->semantic_stack );

    d->abstract_root = make_node ( '^', NULL, NULL );
    d->abstract_root->right = pop ( d->abstract_stack );
    d->abstract_root->left = pop ( d->abstract_stack );
    push ( d->abstract_root, d->abstract_stack );
}

PRIVATE 
void Negate ( action_t  *d )
{
    d->answer = pop ( d->semantic_stack );
    push ( - d->answer, d->semantic_stack );

    d->abstract_root = make_node ( '-', NULL, NULL );
    d->abstract_root->left = pop ( d->abstract_stack );
    push ( d->abstract_root, d->abstract_stack );
}

PRIVATE 
void Push ( action_t  *d )
{
    push ( get_last_attribute(d->peeker), d->semantic_stack );

    d->abstract_root = make_node ( get_last_attribute(d->peeker), NULL, NULL );
    push ( d->abstract_root, d->abstract_stack );
}

void DumpStack ( action_t  *d )
{
    dump_stack ( d->semantic_stack );
}

#include "SlkExecute.txt"

// ------------------------------------------------------------------
// InitializeAction 
// ------------------------------------------------------------------ 

PUBLIC
void
InitializeAction ( action_t  *action,
                   int        display,
                   peeker_t  *peeker )
{              
    InitializeTree ( &action->tree, display, peeker );

    action->peeker = peeker;
    action->answer = 0.0;
    action->abstract_root = NULL;
    action->abstract_stack.top = action->abstract_stack.start + STACKSIZE - 1;
    action->abstract_stack.end = action->abstract_stack.start + STACKSIZE - 1;
    action->semantic_stack.top = action->semantic_stack.start + STACKSIZE - 1;
    action->semantic_stack.end = action->semantic_stack.start + STACKSIZE - 1;

    action->execute = execute;
    action->state = state;
    action->predict = action->tree.predict;
    action->reduce = action->tree.reduce;

    action->show_tree = action->tree.show_tree;
    action->show_parse_derivation = action->tree.show_parse_derivation;
    action->post_order = post_order;
}
